package com.tarena.lbs.business.servcie.Impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.basic.pojo.po.AreaPO;
import com.tarena.lbs.basic.service.AreaService;
import com.tarena.lbs.business.base.enums.BusinessGroupResultEnum;
import com.tarena.lbs.business.dao.repository.BusinessRepository;
import com.tarena.lbs.business.dao.repository.StoreESRepository;
import com.tarena.lbs.business.dao.repository.StoreRepository;
import com.tarena.lbs.business.pojo.entity.StoreSearchMessage;
import com.tarena.lbs.business.pojo.param.StoreParam;
import com.tarena.lbs.business.pojo.param.UserLocationParam;
import com.tarena.lbs.business.pojo.po.BusinessPO;
import com.tarena.lbs.business.pojo.po.StorePO;
import com.tarena.lbs.business.pojo.po.StoreSearchPO;
import com.tarena.lbs.business.pojo.query.AreaStoreQuery;
import com.tarena.lbs.business.pojo.query.StoreChainQuery;
import com.tarena.lbs.business.pojo.query.StoreQuery;
import com.tarena.lbs.business.pojo.vo.StoreChainVO;
import com.tarena.lbs.business.pojo.vo.StoreVO;
import com.tarena.lbs.business.servcie.StoreService;
import com.tarena.lbs.common.enums.PassportResultEnum;
import com.tarena.lbs.common.enums.Roles;
import com.tarena.lbs.common.principle.UserPrinciple;
import com.tarena.lbs.common.utils.AuthenticationContextUtils;
import com.tarena.lbs.user.api.UserApi;
import com.tarena.lbs.user.api.pojo.dto.AdminDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class StoreServiceImpl implements StoreService {
    @Autowired
    private StoreRepository storeRepository;
    @DubboReference
    private UserApi userApi;
    @DubboReference
    private AreaService areaService;
    @Autowired
    private StoreESRepository storeESRepository;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private BusinessRepository businessRepository;
    // 添加ObjectMapper实例
    private final ObjectMapper objectMapper = new ObjectMapper();




    @Override
    public void saveStore(StoreParam param) throws BusinessException {
        log.info("新增店铺参数:{}", param);
        checkLoginSHOP(Roles.SHOP);
        StorePO storePO = new StorePO();
        BeanUtils.copyProperties(param,storePO);
        if (storePO.getStoreLogo() == null){
            storePO.setStoreLogo("图片null.jpg");
        }
        if(param.getStoreStatus() == 1){
            storePO.setStoreStatus(-1);
        }else {
            storePO.setStoreStatus(0);
        }
        storePO.setStoreLongitude(param.getLongitude());
        storePO.setStoreLatitude(param.getLatitude());
        if(param.getId() != null){
            storePO.setUpdateTime(new Date());
            storeRepository.updateById(storePO);
        }
        storePO.setCreateTime(new Date());
        storePO.setUpdateTime(new Date());
        log.info("新增店铺PO:{}", storePO);
        storeRepository.save(storePO);

    }
    @Override
    public PageResult<StoreVO> pageList(StoreQuery query) throws BusinessException {
        log.info("分页查询店铺参数:{}", query);
        PageResult<StoreVO> pageResult = new PageResult<>(query);
        List<StoreVO> storeVOList;
        checkLoginSHOP(Roles.SHOP);
        List<StorePO> storePOList = storeRepository.pageList(query);
        if(storePOList == null || storePOList.isEmpty()){
            log.info("分页查询店铺结果为空");
            pageResult.setTotal(0L);
            return pageResult;
        }
        log.info("分页查询店铺结果:{}", storePOList);
        storeVOList = new ArrayList<>();
        for (StorePO storePO : storePOList) {
            StoreVO storeVO = new StoreVO();
            BeanUtils.copyProperties(storePO,storeVO);
            storeVOList.add(storeVO);
        }
        pageResult.setTotal((long) storePOList.size());
        pageResult.setObjects(storeVOList);

        return pageResult;
    }

    @Override
    public PageResult<StoreVO> getStoreByCity(AreaStoreQuery query) throws BusinessException {
        log.info("根据地市查询店铺参数:{}", query);
        PageResult<StoreVO> pageResult = new PageResult<>(query);
        List<StoreVO> storeVOList;
        checkLoginSHOP(Roles.SHOP);
        List<Long> cityIdList = query.getCityIdList();
        Long adCode = cityIdList.get(2);
        AreaPO areaPO = areaService.selectById(adCode);
        //获取该区域id
        Long areaId = areaPO.getId();
        log.info("该区域id:{}", areaId);
        List<StorePO> storePOList = storeRepository.getStoreByCity(areaId);
        if(storePOList == null || storePOList.isEmpty()){
            log.info("分页查询店铺结果为空");
            pageResult.setTotal(0L);
            return pageResult;
        }
        storeVOList = new ArrayList<>();
        for (StorePO storePO : storePOList) {
            StoreVO storeVO = new StoreVO();
            BeanUtils.copyProperties(storePO,storeVO);
            storeVOList.add(storeVO);
        }
        log.info("分页查询店铺结果:{}", storePOList);
        pageResult.setTotal((long) storePOList.size());
        pageResult.setObjects(storeVOList);
        return pageResult;
    }

    @Override
    public void enable(Integer id) {
        log.info("店铺状态切换参数:{}", id);
        StorePO storePO = storeRepository.selectByStoreId(id);
        storePO.setStoreStatus(storePO.getStoreStatus() == 0 ? 1 : 0);
        storeRepository.updateById(storePO);
    }

    @Override
    public StoreVO selectByStoreId(Integer id) {
        log.info("查询店铺参数:{}", id);
        StorePO storePO = storeRepository.selectByStoreId(id);
        log.info("查询店铺storePO结果:{}", storePO);
        StoreVO storeVO = new StoreVO();
        BeanUtils.copyProperties(storePO,storeVO);
        storeVO.setLatitude(storePO.getStoreLatitude());
        storeVO.setLongitude(storePO.getStoreLongitude());
        if(storeVO.getStoreStatus() == 0){
            storeVO.setStoreStatus(0);
        }else {
            storeVO.setStoreStatus(1);
        }

        log.info("查询店铺storeVO结果:{}", storeVO);
        return storeVO;
    }

    @Override
    public void delete(Integer id) {
        log.info("删除店铺参数:{}", id);
        storeRepository.deleteById(id);
    }

    @Override
    public void location(UserLocationParam param) throws BusinessException {
        log.info("用户经纬度查询附近店铺参数:{}", param);
        
        // 获取用户经纬度
        String latitudeStr = param.getLatitude();
        String longitudeStr = param.getLongitude();
        
        if (latitudeStr == null || longitudeStr == null) {
            throw new BusinessException(BusinessGroupResultEnum.PARAM_ERROR);
        }
        
        try {
            Double userLat = Double.parseDouble(latitudeStr);
            Double userLon = Double.parseDouble(longitudeStr);
            
            log.info("用户经纬度: 纬度={}, 经度={}", userLat, userLon);
            
            // 定义查询距离范围：5km, 10km, 15km, 20km
            double[] distances = {5.0, 10.0, 15.0, 20.0};
            List<StoreSearchPO> allStores = new ArrayList<>();
            double finalDistance = 5.0;
            
            // 逐步扩大查询范围，直到找到至少5个店铺或达到最大范围
            for (double distance : distances) {
                log.info("查询{}km范围内的店铺", distance);
                List<StoreSearchPO> nearbyStores = storeESRepository.findStoresWithinDistance(userLat, userLon, distance);
                log.info("{}km范围内查询到{}个店铺", distance, nearbyStores.size());
                
                if (!nearbyStores.isEmpty()) {
                    // 去重：只添加之前没有的店铺
                    for (StoreSearchPO store : nearbyStores) {
                        if (allStores.stream().noneMatch(s -> s.getId().equals(store.getId()))) {
                            allStores.add(store);
                        }
                    }
                    
                    log.info("累计查询到{}个店铺", allStores.size());
                    
                    // 如果已经找到至少5个店铺，停止扩大范围
                    if (allStores.size() >= 5) {
                        finalDistance = distance;
                        log.info("在{}km范围内找到足够店铺，停止扩大查询范围", distance);
                        break;
                    }
                }
                
                finalDistance = distance; // 记录当前查询的距离
            }
            
            // 如果所有范围内都没有店铺，抛出异常
            if (allStores.isEmpty()) {
                log.warn("在20km范围内未找到任何店铺");
                throw new BusinessException(BusinessGroupResultEnum.STORE_NOT_FOUND);
            }
            
            log.info("最终在{}km范围内找到{}个店铺", finalDistance, allStores.size());
            
            // 优化：计算距离并排序，只取最近的5个店铺
            List<StoreSearchPO> nearestStores = new ArrayList<>();
            if (!allStores.isEmpty()) {
                // 计算每个店铺到用户的距离
                for (StoreSearchPO store : allStores) {
                    double storeDistance = calculateDistance(userLat, userLon, 
                        Double.parseDouble(store.getStoreLatitude()), 
                        Double.parseDouble(store.getStoreLongitude()));
                    log.info("店铺ID: {}, 距离用户: {:.2f}km", store.getId(), storeDistance);
                }
                
                // 按距离排序（升序）
                allStores.sort((s1, s2) -> {
                    double dist1 = calculateDistance(userLat, userLon, 
                        Double.parseDouble(s1.getStoreLatitude()), Double.parseDouble(s1.getStoreLongitude()));
                    double dist2 = calculateDistance(userLat, userLon, 
                        Double.parseDouble(s2.getStoreLatitude()), Double.parseDouble(s2.getStoreLongitude()));
                    return Double.compare(dist1, dist2);
                });
                
                // 只取最近的5个店铺
                int count = Math.min(5, allStores.size());
                for (int i = 0; i < count; i++) {
                    nearestStores.add(allStores.get(i));
                    double finalStoreDistance = calculateDistance(userLat, userLon, 
                        Double.parseDouble(allStores.get(i).getStoreLatitude()), 
                        Double.parseDouble(allStores.get(i).getStoreLongitude()));
                    log.info("最近的店铺 {}: ID={}, 距离={:.2f}km", i+1, allStores.get(i).getId(), finalStoreDistance);
                }
            }
            
            log.info("筛选后最近的{}个店铺", nearestStores.size());
            
            // 转换为VO对象（只转换最近的5个）
            List<StoreVO> storeVOList = new ArrayList<>();
            for (StoreSearchPO storeSearchPO : nearestStores) {
                StoreVO storeVO = new StoreVO();
                BeanUtils.copyProperties(storeSearchPO, storeVO);
                storeVO.setLatitude(storeSearchPO.getStoreLatitude());
                storeVO.setLongitude(storeSearchPO.getStoreLongitude());
                storeVOList.add(storeVO);
            }
            
            log.info("最终返回{}个店铺给前端，查询范围{}km", storeVOList.size(), finalDistance);
            
            // 发送消息到RabbitMQ
            sendStoreSearchMessage(param, nearestStores, userLat, userLon, finalDistance);
            
        } catch (NumberFormatException e) {
            log.error("经纬度参数格式错误: latitude={}, longitude={}", latitudeStr, longitudeStr);
            throw new BusinessException(BusinessGroupResultEnum.PARAM_ERROR);
        }
    }

    //二维码管理
    @Override
    public PageResult<StoreChainVO> pageList(StoreChainQuery query) throws BusinessException {
        log.info("分页查询店铺参数:{}", query);
        PageResult<StoreChainVO> pageResult = new PageResult<>(query);
        List<StoreChainVO> storeVOList;
        checkLoginSHOP(Roles.SHOP);
        List<Long> cityIdList = query.getStoreAddress();
        String storeName = query.getStoreName();
        Long areaId = null;
        if(cityIdList != null){
            Long adCode = cityIdList.get(2);
            AreaPO areaPO = areaService.selectById(adCode);
            //获取该区域id
            areaId = areaPO.getId();
        }
        log.info("该区域id:{}", areaId);
        List<StorePO> storePOList = storeRepository.pageList(areaId,storeName);
        if(storePOList == null || storePOList.isEmpty()){
                log.info("分页查询店铺结果为空");
                pageResult.setTotal(0L);
                return pageResult;
        }
        log.info("分页查询店铺结果:{}", storePOList);
        storeVOList = new ArrayList<>();
        for (StorePO storePO : storePOList) {
            StoreChainVO storeChainVO = new StoreChainVO();
            storeChainVO.setId(storePO.getId());
            storeChainVO.setStoreAddress(storePO.getStoreLocation());
            BusinessPO businessPO = businessRepository.selectById(storePO.getBusinessId());
            storeChainVO.setBusinessName(storePO.getStoreName());
            storeChainVO.setLink("www.baidu.com");
            storeChainVO.setStoreName(businessPO.getBusinessName());
            //没有链接相关信息，暂用店铺状态
            if(storePO.getStoreStatus() == 0){
                storeChainVO.setLinkStatus(1);
            }else {
                storeChainVO.setLinkStatus(0);
            }
            storeVOList.add(storeChainVO);
        }
        log.info("分页查询店铺结果:{}", storeVOList);
        pageResult.setTotal((long) storeVOList.size());
        pageResult.setObjects(storeVOList);
        log.debug("分页查询店铺业务,pageResult={}", pageResult);
        return pageResult;
    }

    // 添加距离计算方法
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double earthRadius = 6371; // 地球半径，单位：km
        
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                   Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                   Math.sin(dLon / 2) * Math.sin(dLon / 2);
        
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return earthRadius * c;
    }

    // 发送店铺搜索消息到RabbitMQ
    private void sendStoreSearchMessage(UserLocationParam param, List<StoreSearchPO> nearestStores, 
                                       Double userLat, Double userLon, Double finalDistance) {
        try {
            // 获取用户ID
            Long userId = Long.valueOf(param.getUserId());
            if (userId == null) {
                log.warn("用户ID为空，跳过RabbitMQ消息发送");
                return;
            }
            
            // 提取店铺ID列表
            List<Long> storeIds = new ArrayList<>();
            for (StoreSearchPO nearestStore : nearestStores) {
                Integer id = nearestStore.getId();
                storeIds.add(Long.valueOf(id));
            }

            // 创建消息对象
            StoreSearchMessage message = new StoreSearchMessage(userId, storeIds, userLat, userLon, finalDistance);

            // 将Java对象转换为JSON字符串
            String jsonMessage = objectMapper.writeValueAsString(message);

            // 发送JSON消息到RabbitMQ
            rabbitTemplate.convertAndSend("store.search.queue", jsonMessage);

            log.info("成功发送店铺搜索消息到RabbitMQ: 用户ID={}, 店铺数量={}, 查询范围={}km",
                    userId, storeIds.size(), finalDistance);
            log.info("JSON消息内容: {}", jsonMessage);
            
        } catch (Exception e) {
            log.error("发送RabbitMQ消息失败: {}", e.getMessage(), e);
            // 消息发送失败不影响主流程，只记录日志
        }
    }

    private void checkLoginSHOP(Roles role) throws BusinessException {
        //检验用户是否登录
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        if (userPrinciple == null){
            throw new BusinessException(PassportResultEnum.USER_NOT_LOGIN);
        }
        AdminDto adminDto = userApi.getAdminById(userPrinciple.getId());
        BusinessPO businessPO = storeRepository.selectByBusinessId(adminDto.getBusinessId());
        //检验商家是否存在
        if(businessPO == null){
            throw new BusinessException(BusinessGroupResultEnum.USER_ROLE_ERROR);
        }
        //检验用户角色是否是商家
        if(role != userPrinciple.getRole()){
            throw new BusinessException(BusinessGroupResultEnum.USER_ROLE_ERROR);
        }
    }
}